﻿using PlantSystem;
using Sirenix.OdinInspector;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace AniyaDesign
{
    public class DesignManager : MonoBehaviour
    {

        public GameObject giantGroundGO;

        public TerrainType designTerrainType;
        public TerrainLandStatus designTerrainLandStatus;

        public int terrainSize = 200;

        public Transform SunLightTrans;
        public Light SunLight;

        [Range(0, 24)]
        [OnValueChanged("UpdateDayNight")]
        public float hourTime = 11f;

        public float MaxHeight = 10f;
        public float TerrainScale = 1f;

        public Transform TreesNode;

        public Transform MainRole;

        [BoxGroup("天空盒环境光")]
        [LabelText("白天环境光")]
        public GradientColor DayAmbientColor;
        [BoxGroup("天空盒环境光")]
        [LabelText("夜晚环境光")]
        public GradientColor NightAmbientColor;
        [BoxGroup("天空盒环境光")]
        [LabelText("黄昏环境光")]
        public GradientColor DuskAmbientColor;

        [LabelText("阴影倾斜角度")]
        public AnimationCurve SunShadowAngleCurve = new AnimationCurve(
            new Keyframe(0, 0),
            new Keyframe(6, 60),
            new Keyframe(12, 0),
            new Keyframe(18, -60),
            new Keyframe(24, 0));

        [LabelText("阴影方向角度")]
        public AnimationCurve SunShadowDirectionCurve = new AnimationCurve(
            new Keyframe(0, 0),
            new Keyframe(6, 90),
            new Keyframe(12, 180),
            new Keyframe(18, 270),
            new Keyframe(24, 360));

        [LabelText("太阳月亮颜色，随时间变化")]
        public Gradient SunColorOverTime;
        [LabelText("环境光渐变，随时间变化，0为夜，1为日，2为黄昏，3为夜")]
        public AnimationCurve AmbientColorCurve = new AnimationCurve(
            new Keyframe(0, 0),
            new Keyframe(5, 0),
            new Keyframe(7, 1),
            new Keyframe(12, 1),
            new Keyframe(15.5f, 1),
            new Keyframe(18, 2),
            new Keyframe(20, 3),
            new Keyframe(24, 3)
            );

        [Button("创建地面")]
        public void BuildGround()
        {

            var size = terrainSize + 1;
            var terrainColorTexture = new Texture2D(size, size, TextureFormat.RGBAHalf, false)
            {
                filterMode = FilterMode.Bilinear
            };
            var gridData = new TerrainGridData()
            {
                terrainType = designTerrainType,
                landStatus = designTerrainLandStatus
            };

            for (int i = 0; i < size; i++)
            {
                for (int j = 0; j < size; j++)
                {
                    var terrainPos = new Vector2Int(i, j);
                    terrainColorTexture.SetPixel(i, j, GetTerrainGridColor(ref terrainPos, ref gridData));
                }
            }

            terrainColorTexture.Apply();

            var normalHeightMapTexture = CalculateGroundNormalHeight(ref gridData);

            var giantGroundRdr = giantGroundGO.GetComponent<MeshRenderer>();
            var mat = giantGroundRdr.material;
            mat.SetTexture(ShaderConst.SID_MainTex, terrainColorTexture);
            mat.SetTexture(ShaderConst.SID_NormalTex, normalHeightMapTexture);
            mat.SetFloat("_UVScale", terrainSize * 2);
            giantGroundRdr.material = mat;
            //giantGroundRdr.sharedMaterial = mat;
        }

        private float GetGroundHeight(float x, float y)
        {
            var pr = Mathf.PerlinNoise(x / TerrainScale, y / TerrainScale);
            return Mathf.Lerp(0, MaxHeight, pr);
        }

        private Color GetTerrainGridColor(ref Vector2Int terrainPos, ref TerrainGridData gridData)
        {

            var terrain = gridData.terrainType;
            var landStatus = gridData.landStatus;
            var marginIdx = gridData.marginIdx;

            if (landStatus == TerrainLandStatus.Grass)
            {

                if (terrain == TerrainType.DelonixRegia)
                    return TerrainConst.RedGrassColorLiner;
                else if (terrain == TerrainType.RockField ||
                    terrain == TerrainType.MixRockField)
                    return TerrainConst.RockGrassColorLiner;
                else if (terrain == TerrainType.AdvancedRockField)
                    return TerrainConst.AdvancedRockGrassColorLiner;
                else if (terrain == TerrainType.ColdLooseWood ||
                        terrain == TerrainType.ColdMidWood ||
                        terrain == TerrainType.ColdPlain)
                    return TerrainConst.ColdGrassColorLiner;
                else if (terrain == TerrainType.Marsh)
                {
                    return TerrainConst.TerrainGroundColors[terrain];
                }
                else if (terrain == TerrainType.DecayBlack || terrain == TerrainType.SnowField)
                {
                    return TerrainConst.TerrainGroundColors[terrain];
                }
                else if (terrain == TerrainType.PeachWood)
                {
                    return TerrainConst.PeachGrassColorLiner;
                }
                else
                {
                    return TerrainConst.GrassColorLiner;
                }
            }
            else if (terrain == TerrainType.PeachWood)
            {
                var rate = Mathf.Clamp01((marginIdx - 1) * 0.2f);
                return Color.Lerp(TerrainConst.BareLandGroundColor, TerrainConst.TerrainGroundColors[terrain], rate * rate);
            }
            else if (/*landStatus == TerrainLandStatus.Bare || */landStatus == TerrainLandStatus.TotallyBare)
            {
                if (landStatus == TerrainLandStatus.TotallyBare)
                    return TerrainConst.BareLandGroundColor;
                else
                    return TerrainConst.TerrainGroundColors[terrain];
            }
            else if (landStatus == TerrainLandStatus.RiverWay)
            {
                return TerrainConst.TerrainGroundColors[terrain] * 0.7f;
            }
            else
            {
                var colorOffset = Mathf.PerlinNoise(60 + terrainPos.x * 0.5f, 60 + terrainPos.y * 0.5f) * 0.2f;
                return Color.Lerp(TerrainConst.TerrainGroundColors[terrain], Color.black, colorOffset);
            }
        }
#if UNITY_EDITOR
        [Button("刷新树")]
        public void RefreshTrees()
        {
            var cnt = TreesNode.childCount;
            var posRange = terrainSize;
            for (int i = 0; i < cnt; i++)
            {
                var tree = TreesNode.GetChild(i);
                var pos = new Vector3(
                    Mathf.Lerp(0, posRange, Random.Range(0, 1f)), 0,
                    Mathf.Lerp(0, posRange, Random.Range(0, 1f)));
                //var sx = (pos.x + terrainSize * 2) % (terrainSize * 2);
                //var sz = (pos.z + terrainSize * 2) % (terrainSize * 2);
                var sx = pos.x;
                var sz = pos.z;
                var height = GetGroundHeight(sx, sz);
                pos.y = height;
                tree.localPosition = pos;
                tree.localRotation = Quaternion.Euler(0, Random.Range(0, 360), 0);
                tree.localScale = Vector3.one * Random.Range(0.8f, 1.2f);
                var plc = tree.GetComponent<PlantLifeCycle>();
                if (plc != null)
                {
                    var r = Random.Range(0, 1f);
                    if (r < 0.4f)
                        plc.status = PlantLifeStatus.OLD;
                    else if (r < 0.7f)
                        plc.status = PlantLifeStatus.ADULT;
                    else
                        plc.status = PlantLifeStatus.YOUNG;
                    plc.RefreshStatusShow();
                }
            }

            var mainrolePos = new Vector3(posRange * 0.5f, 0, posRange * 0.5f);
            mainrolePos.y = GetGroundHeight(mainrolePos.x, mainrolePos.z);
            MainRole.position = mainrolePos;
        }
#endif

        public Texture2D CalculateGroundNormalHeight(ref TerrainGridData gridData, float bumpEffect = 1f)
        {
            var size = terrainSize + 1;// terrainGridDatas.Length;
            var normalHeightMapTexture = new Texture2D(size, size, TextureFormat.RGBAHalf, false);
            normalHeightMapTexture.filterMode = FilterMode.Bilinear;

            for (int i = 0; i < size; i++)
            {
                for (int j = 0; j < size; j++)
                {
                    //var height = gridData.groundHeight * 0.01f;
                    var rx = 1f * i / size;
                    var rz = 1f * j / size;
                    var fx = Mathf.Lerp(0, terrainSize * 2, rx);
                    var fz = Mathf.Lerp(0, terrainSize * 2, rz);
                    var height = GetGroundHeight(fx, fz) * 0.01f;

                    normalHeightMapTexture.SetPixel(i, j, new Color(1, 1, 1, height));
                }
            }
            normalHeightMapTexture.Apply();

            var rd = new RenderTextureDescriptor(normalHeightMapTexture.width, normalHeightMapTexture.height);
            rd.sRGB = false;
            var rt = RenderTexture.GetTemporary(rd);
            var mat = new Material(Shader.Find("Aniya/Height2NormalMap"));
            bumpEffect = 1f;// 0.5f;
            float v = bumpEffect * 2f - 1f;
            float z = 1f - v;
            float xy = 1f + v;
            mat.SetVector("_Factor", new Vector4(xy, xy, z, 1));

            Graphics.Blit(normalHeightMapTexture, rt, mat, 0);

            RenderTextureToTexture2D(rt, normalHeightMapTexture);

            RenderTexture.ReleaseTemporary(rt);
            rt = null;

            return normalHeightMapTexture;
        }

        [System.Serializable]
        public struct GradientColor
        {
            public Color SkyColor;
            public Color EquatorColor;
            public Color GroundColor;

            public void SetToRenderSetting()
            {
                RenderSettings.ambientSkyColor = SkyColor;
                RenderSettings.ambientEquatorColor = EquatorColor;
                RenderSettings.ambientGroundColor = GroundColor;
            }

            public static GradientColor Lerp(GradientColor c1, GradientColor c2, float rate)
            {
                return new GradientColor()
                {
                    SkyColor = Color.Lerp(c1.SkyColor, c2.SkyColor, rate),
                    EquatorColor = Color.Lerp(c1.EquatorColor, c2.EquatorColor, rate),
                    GroundColor = Color.Lerp(c1.GroundColor, c2.GroundColor, rate)
                };
            }
        }

        private void RenderTextureToTexture2D(RenderTexture renderTexture, Texture2D texture2D)
        {

            RenderTexture currentRT = RenderTexture.active;

            RenderTexture.active = renderTexture;
            texture2D.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
            texture2D.Apply();

            RenderTexture.active = currentRT;
        }

        private void UpdateDayNight()
        {
            var hourTimeRate = hourTime / 24f;

            var ambientFac = AmbientColorCurve.Evaluate(hourTime);

            RenderSettings.skybox.SetFloat("_DayToNight", ambientFac);

            if (ambientFac < 1f)
            {
                GradientColor.Lerp(NightAmbientColor, DayAmbientColor, ambientFac).SetToRenderSetting();
            }
            else if (ambientFac < 2f)
            {
                GradientColor.Lerp(DayAmbientColor, DuskAmbientColor, ambientFac - 1).SetToRenderSetting();
            }
            else
            {
                GradientColor.Lerp(DuskAmbientColor, NightAmbientColor, ambientFac - 2).SetToRenderSetting();
            }

            var shadowAngle = SunShadowAngleCurve.Evaluate(hourTime);
            var shadowDirection = SunShadowDirectionCurve.Evaluate(hourTime);
            SunLightTrans.localRotation = Quaternion.Euler(shadowAngle, shadowDirection, 0);

            SunLight.color = SunColorOverTime.Evaluate(hourTimeRate);
        }

    }
}